#!/usr/bin/python

import os
import re
import sys

import logging
import os.path
import time

from guplib.gallery import Gallery, GalleryError
from guplib.albums import AlbumList, AlbumDoesntExistError
from optparse import OptionParser
from ConfigParser import ConfigParser
from urllib2 import HTTPError
from Tkinter import *
from picasa2gallerywindow_ui import Picasa2gallerywindow
from tkMessageBox import *
from gup import *
from guplib.gallery import InvalidPasswordError

# BEGIN USER CODE global

# END USER CODE global

class CustomPicasa2gallerywindow(Picasa2gallerywindow):

    def __init__(self, master):
        Picasa2gallerywindow.__init__(self, master)
        self.__master = master
        self.uploading = False

    # defaultCheckBox_command --
    #
    # Callback to handle defaultCheckBox widget option -command
    def defaultCheckBox_command(self, *args):
        pass

    def setOptionsFromUI(self, options):
        options.url = self.urlEntry.get()
        options.password = self.passwordEntry.get()
        options.user = self.usernameEntry.get()
        options.default = bool(self.defaultCheckBoxVar.get())

    # parentAlbumRefresh_command --
    #
    # Callback to handle parentAlbumRefresh widget option -command
    def parentAlbumRefresh_command(self, *args):
        self.statusLabel.configure(text='Status: Loading data from server ...')
        self.__master.update_idletasks()
        self.options.reload=True
        self.setOptionsFromUI(self.options)
        self.setAlbums( check_album_cache(self.galleryDropDown.get(), self.options)[0] )
        self.options.reload=False
        save_album_cache(self.galleryDropDown.get(), self.albums)
        self.statusLabel.configure(text='Status: Done')

    def parentAlbumDropDown_selected(self, *args):
        pass

    # quitButton_command --
    #
    # Callback to handle quitButton widget option -command
    def quitButton_command(self, *args):
        self.__master.destroy()

    # saveButton_command --
    #
    # Callback to handle saveButton widget option -command
    def saveButton_command(self, *args):

        galleryName = self.galleryDropDown.get()

        if (not galleryName):
            showwarning('Warning', 'You must enter a name for your gallery before saving')
            return

        self.setOptionsFromUI(self.options)

        try:
            connection = Gallery(self.options.url, self.options.user,
                                 self.options.password)
            connection.login()
        except Exception, e:
            showerror('Ok', e)
            return

#        self.__master.configure(cursor='exchange')
        self.statusLabel.configure(text='Status: Saving data ...')
        self.__master.update_idletasks()
        
        self.parentAlbumRefresh_command(self, args)        
        save_gallery_info(self.configuration, galleryName, self.options)
        self.statusLabel.configure(text='Status: Done ...')

    # uploadButton_command --
    #
    # Callback to handle uploadButton widget option -command
    def uploadButton_command(self, *args):
        self.postImages()

    # END CALLBACK CODE

    # BEGIN USER CODE class

    def setGalleryNameList(self, galleryNames):
        if (len(galleryNames) == 1):
            self.defaultCheckBox.select()
            
        self.galleryDropDown.setlist(galleryNames)

    def locate_gallery(self, configuration, name):
        '''Look for a gallery in the configuration, or return the name of one
        if there is only one gallery.'''
        if name:
            if not configuration.has_section(name):
                raise NoSuchGalleryError, name
            return name

        sections = configuration.sections()
        if len(sections) == 0:
            return ''
        elif len(sections) == 1:
            return sections[0]
        else:
            # look for default
            for section in sections:
                if configuration.has_option(section, 'default'):
                    if self.configuration.getboolean(gallery, 'default'):
                        return section
        return ''
                

    def galleryDropDown_selection(self, *args):

        galleryName = args[0]

        if not galleryName:
            self.defaultCheckBox.deselect()
            self.usernameEntry.delete(0,END)
            self.urlEntry.delete(0,END)           
            self.passwordEntry.delete(0,END)
            return
        
        gallery = self.locate_gallery(self.configuration, galleryName)

        if self.usernameEntry.get():
            self.usernameEntry.delete(0,END)
        if self.configuration.has_option(gallery, 'user'):
            self.usernameEntry.insert(0, self.configuration.get(gallery, 'user'))

        if self.urlEntry.get():
            self.urlEntry.delete(0,END)
        if self.configuration.has_option(gallery, 'url'):
            self.urlEntry.insert(0, self.configuration.get(gallery, 'url'))

        if self.passwordEntry.get():
            self.passwordEntry.delete(0,END)
        if self.configuration.has_option(gallery, 'password'):
            self.passwordEntry.insert(0, self.configuration.get(gallery, 'password'))

        if self.configuration.has_option(gallery, 'default'):
            if self.configuration.getboolean(gallery, 'default'):
                self.defaultCheckBox.select()
            else:
                self.defaultCheckBox.deselect()

        self.setAlbums( check_album_cache(self.galleryDropDown.get(), self.options)[0] )
                

    def setConfig(self,config) :
        self.configuration = config
        defaultName = self.locate_gallery(self.configuration, '')
        if (not defaultName == ''):
            self.galleryDropDown.selectitem(defaultName)
            self.galleryDropDown_selection(defaultName, )

    def setAlbums(self, albums) :
        self.albums = albums
        self.parentAlbumDropDown.setlist( self.getSpacedAlbumList(self.albums) )

    def setOptions(self, options) :
        self.options = options

    def setFiles(self, files) :
        self.files = files

    def getSpacedAlbumList(self, albums):
        albumList = []

        for (level, name, album_id) in albums.tree():
            mystr = '%s%s' % ('  ' * level, name)
            albumList.append(mystr)
        
        return albumList[1:]

    def close_handler(self, root):
        if (self.uploading):
            if (askyesno("Don't hit yes", 'Upload is still in progress.  Do you really really want to exit?')):
                root.destroy()
                sys.exit(0)
            else:
                return
            
        root.destroy()

    def getAlbumIdForName(self, albums, album_name):
        possibleAlbums = albums.search_name(album_name)
        for (level, name, album_id) in possibleAlbums.tree():    
            if (album_name == name):
                return album_id
        return None

    def createAlbumWithParent(self, newAlbumName, parentName, albums):
        # check this.
        newAlbumFileName = str(newAlbumName)
        newAlbumFileName = makeFileName(newAlbumFileName);

        self.__master.update_idletasks()

        parentAlbumId = self.getAlbumIdForName(albums, parentName)
        if (not parentAlbumId):
            self.statusLabel.configure(text='Error creating album under ' + parentName)
            return

        self.statusLabel.configure(text='Creating new album named ' + newAlbumName)
        connection = Gallery(self.options.url, self.options.user,
                             self.options.password)
        album_id = connection.new_album(str(parentAlbumId),
                                        str(newAlbumFileName), str(newAlbumName))
        if album_id is not None:
            logging.info('Created new album "%s", id "%s"' %
                         (newAlbumName, album_id))
            self.statusLabel.configure(text='Successfully created album ' + newAlbumName)
            self.options.album = album_id
        else:
            self.statusLabel.configure(text='Error creating album ' + newAlbumName)
            return

        albums.add(album_id, newAlbumName,
                   parentAlbumId)

        self.setAlbums(albums)
        
    def postImages(self):
        selectedParent = self.parentAlbumDropDown.get()
        selectedParent = selectedParent.strip(' ')

        if (self.newAlbumEntry.get()):
            self.createAlbumWithParent(self.newAlbumEntry.get(), selectedParent, self.albums )
        else :
            try:
                self.options.album = self.getAlbumIdForName(self.albums, selectedParent)
            except AlbumDoesntExistError, e:
                showerror('Ok', 'The album ' + self.albums + ' already exists')
                logging.error('There isn''t an album named "%s"',
                              selectedParent)
                return
            
        self.upload()

    def upload(self):
        '''Upload files to the gallery.'''

        self.uploading = True
        
        connection = Gallery(self.options.url, self.options.user, self.options.password)
        total = len(self.files)
        current = 0
        for image in self.files:
            current += 1
            statusString = 'Uploading "%s" (%d/%d) ...' % (image, current, total)
            logging.info(statusString)
            time.sleep(.1)
            self.__master.update_idletasks()
            self.statusLabel.configure(text=statusString)
            try:
                self.__master.update()
                connection.add_item(str(self.options.album), image)
                if self.options.delete:
                    logging.info('Removing "%s"...', image)
                    os.remove(image)
                statusString = 'Done with "%s"' % image
                logging.info(statusString)
                self.__master.update_idletasks()                
                self.statusLabel.configure(text=statusString)
                
            except HTTPError, e:
                showerror('Ok', 'There was an error while adding the image ' + image + ' : ' + e)
                logging.error('HTTP error: %s' % (e))

        self.__master.update_idletasks()
        self.statusLabel.configure(text='Done with upload')

        self.uploading = False        
        self.__master.destroy()
    

    # END USER CODE class

def makeFileName(albumName):
    badCharacterList = [' ','|', ';',',','!','@','#','$','(',')','<','>','/','"','\\','`','~','{','}','[',']','=','+','&','^','*?']
    substituteChar = '_'
    for badChar in badCharacterList:
        albumName = albumName.replace(badChar, substituteChar)
    return albumName




def getAlbumsOptionsConfigAndFiles() :
    (options, files) = parse_command_line()

    if options.verbose:
        logging_level = logging.DEBUG
    else:
        logging_level = logging.ERROR

    logging.basicConfig(level = logging_level,
                        format='%(message)s')

    gallery = ''
    albums = AlbumList()

    # read the config
    config = ConfigParser()
    config.read([os.path.expanduser('~/.gup/config.ini')])

    if (not (options.gallery)):
        options.gallery = ''

    # locate a gallery; if there more than one, try options; if there are
    #    no options for default gallery, bail out
    try:
        gallery = locate_gallery(config, options.gallery)
    except NoSuchGalleryError, gal:
        logging.error('Gallery "%s" doesn''t exist', gal)
        return
    except CantSelectAGalleryError:
        logging.error('There is more than one gallery saved;')
        logging.error('Use the "-g" option to select one.')
        return 

    # merge options
    if gallery:
        options = merge_options(config, gallery, options)

    # if save-options, save the config file
    if options.save:
        save_gallery_info(config, options.save, options)
        gallery = options.save # that's the current gallery now

    # if reload or cache doesn't exist, reload and keep going; mark cache
    #   info as updated
    try:
        if (gallery):
            (albums, save_cache) = check_album_cache(gallery, options)
    except GalleryError, msg:
        logging.error(str(msg))
        return

    return (albums, options, config, files)


def main():

    root = Tk()

    mainWindow = CustomPicasa2gallerywindow(root)
    root.title('picasa2gallery [0.2]')
    root.protocol('WM_DELETE_WINDOW', lambda : mainWindow.close_handler(root))

    (albums, options, config, files) = getAlbumsOptionsConfigAndFiles()

    if (len(files) == 0):
        showerror('No files selected','You must select files in Picasa before pressing the "Gallery" button')
        return 0

    # Set to true because the pbf makes a copy of the files to be exported, but does not clean them up.
    options.delete = True

    mainWindow.setOptions(options)
    mainWindow.setFiles(files)
    mainWindow.setGalleryNameList(config.sections())
    mainWindow.setConfig(config)
    mainWindow.setAlbums(albums)
    
    root.mainloop()

    return 0

if __name__=='__main__':
    sys.exit(main())


